package jp.aist.gtrc.plus.admission.EDF.simulation;

import jp.aist.gtrc.plus.admission.EDF.*;
import java.util.*;
import eduni.simjava.distributions.ContinuousGenerator;
import eduni.simjava.distributions.Sim_normal_obj;
import eduni.simjava.distributions.Sim_uniform_obj;

public class JobArrivalEventGenerator {
   private Clock clock;
   private int interArrivalTime;
   private int jobArrayId = 0;

   private Random rnd;
   private ContinuousGenerator numOfJobsRnd;
   private ContinuousGenerator exeTimeRnd;
   private ContinuousGenerator relativeDeadlineRnd;

   public JobArrivalEventGenerator(Clock clock, int interArrivalTime,int avgNumOfJobs,int varNumOfJobs,int avgExeTime, int varExeTime, int avgRelativeDeadline, int varRelativeDeadline,long seed) {
      this.clock = clock;
      this.interArrivalTime = interArrivalTime;
      this.rnd = new Random(seed);            
      this.numOfJobsRnd = new Sim_uniform_obj("a1",avgNumOfJobs-Math.sqrt(varNumOfJobs),avgNumOfJobs+Math.sqrt(varNumOfJobs),rnd.nextInt(Integer.MAX_VALUE));
      this.exeTimeRnd = new Sim_uniform_obj("a2",avgExeTime-Math.sqrt(varExeTime),avgExeTime+Math.sqrt(varExeTime),rnd.nextInt(Integer.MAX_VALUE));
      this.relativeDeadlineRnd = new Sim_uniform_obj("a3",avgRelativeDeadline-Math.sqrt(varRelativeDeadline),avgRelativeDeadline+Math.sqrt(varRelativeDeadline),rnd.nextInt(Integer.MAX_VALUE));
   } 

/*
 * We've too many negative values from using normal distribution.
 */
//   public JobArrivalEventGenerator(Clock clock, int interArrivalTime,int avgNumOfJobs,int varNumOfJobs,int avgExeTime, int varExeTime, int avgRelativeDeadline, int varRelativeDeadline,long seed) {
//      this.clock = clock;
//      this.interArrivalTime = interArrivalTime;
//      this.rnd = new Random(seed);            
//      this.numOfJobsRnd = new Sim_normal_obj("a1",avgNumOfJobs,varNumOfJobs,rnd.nextInt(Integer.MAX_VALUE));
//      this.exeTimeRnd = new Sim_normal_obj("a2",avgExeTime,varExeTime,rnd.nextInt(Integer.MAX_VALUE));
//      this.relativeDeadlineRnd = new Sim_normal_obj("a3",avgRelativeDeadline,varRelativeDeadline,rnd.nextInt(Integer.MAX_VALUE));
//   } 


   public JobArrivalEvent next() {
      int num = Math.round((float) numOfJobsRnd.sample());
      int exeTime = Math.round((float) exeTimeRnd.sample());
      int deadline = Math.round((float) relativeDeadlineRnd.sample());

      if (num <= 0) {
         throw new RuntimeException("Number of jobs = " + num + " <= 0");
      }
      if (exeTime <= 0) {
         throw new RuntimeException("Execution time of job = " + exeTime + " <= 0");
      }
      if (deadline <= 0) {
         throw new RuntimeException("deadline of job = " + deadline + " <= 0");
      }

      int arrivalTime = nextArrivalTime() + clock.getCurrentTime();
      JobArray jobArray = new JobArray(""+jobArrayId,num,exeTime,arrivalTime + deadline);
      JobArrivalEvent event = new JobArrivalEvent(arrivalTime,jobArray);
      jobArrayId = jobArrayId + 1;
//      System.out.println(event);
      return event;
   }

   private int nextArrivalTime() {
      float temp = (float) Math.log(rnd.nextFloat())*(-interArrivalTime);
      return Math.round(temp);
   }


}

